如何在 Vue 中使用图表库,如 VChart?
问题描述
如何在 Vue 中实现这样的柱状图

解决方案
在 Vue 3.x 中使用 VChart,分两种情况
不同的图表,封装方式都是类似的
代码示例
- 组合式 API
<script setup lang="ts">
import { onMounted, onBeforeUnmount, onUpdated } from "vue";
import { VChart, IChart, ILineChartSpec } from "@visactor/vchart";
interface LineChartProps {
colors?: string[];
}
const props = defineProps<LineChartProps>();
let chart: IChart;
function parseSpec(chartProps: LineChartProps) {
const colors = chartProps.colors ?? [
"#6690F2",
"#70D6A3",
"#B4E6E2",
"#63B5FC",
"#FF8F62",
"#FFDC83",
"#BCC5FD",
"#A29BFE",
"#63C4C7",
"#F68484",
];
return {
type: "line",
data: {
values: [
{ type: "Nail polish", country: "Africa", value: 4229 },
{ type: "Nail polish", country: "EU", value: 4376 },
{ type: "Nail polish", country: "China", value: 3054 },
{ type: "Nail polish", country: "USA", value: 12814 },
{ type: "Eyebrow pencil", country: "Africa", value: 3932 },
{ type: "Eyebrow pencil", country: "EU", value: 3987 },
{ type: "Eyebrow pencil", country: "China", value: 5067 },
{ type: "Eyebrow pencil", country: "USA", value: 13012 },
{ type: "Rouge", country: "Africa", value: 5221 },
{ type: "Rouge", country: "EU", value: 3574 },
{ type: "Rouge", country: "China", value: 7004 },
{ type: "Rouge", country: "USA", value: 11624 },
{ type: "Lipstick", country: "Africa", value: 9256 },
{ type: "Lipstick", country: "EU", value: 4376 },
{ type: "Lipstick", country: "China", value: 9054 },
{ type: "Lipstick", country: "USA", value: 8814 },
{ type: "Eyeshadows", country: "Africa", value: 3308 },
{ type: "Eyeshadows", country: "EU", value: 4572 },
{ type: "Eyeshadows", country: "China", value: 12043 },
{ type: "Eyeshadows", country: "USA", value: 12998 },
{ type: "Eyeliner", country: "Africa", value: 5432 },
{ type: "Eyeliner", country: "EU", value: 3417 },
{ type: "Eyeliner", country: "China", value: 15067 },
{ type: "Eyeliner", country: "USA", value: 12321 },
{ type: "Foundation", country: "Africa", value: 13701 },
{ type: "Foundation", country: "EU", value: 5231 },
{ type: "Foundation", country: "China", value: 10119 },
{ type: "Foundation", country: "USA", value: 10342 },
{ type: "Lip gloss", country: "Africa", value: 4008 },
{ type: "Lip gloss", country: "EU", value: 4572 },
{ type: "Lip gloss", country: "China", value: 12043 },
{ type: "Lip gloss", country: "USA", value: 22998 },
{ type: "Mascara", country: "Africa", value: 18712 },
{ type: "Mascara", country: "EU", value: 6134 },
{ type: "Mascara", country: "China", value: 10419 },
{ type: "Mascara", country: "USA", value: 11261 },
],
},
color: {
type: "ordinal",
domain: [],
range: colors,
},
title: {
visible: true,
text: "Stacked line chart",
},
stack: true,
xField: "type",
yField: "value",
seriesField: "country",
legends: [{ visible: true, position: "middle", orient: "bottom" }],
} as ILineChartSpec;
}
function createOrUpdateChart(chartProps: LineChartProps) {
const container = document.getElementById("treemap-container");
if (container && !chart) {
chart = new VChart(parseSpec(chartProps), {
dom: container,
});
chart.renderSync();
return true;
} else if (chart) {
chart.updateSpec(parseSpec(chartProps));
chart.renderSync();
return true;
}
return false;
}
onMounted(() => {
createOrUpdateChart(props);
});
onUpdated(() => {
createOrUpdateChart(props);
});
onBeforeUnmount(() => {
if (chart) {
chart.release();
}
});
</script>
<template>
<h1>this is a demo of LineChart</h1>
<div class="treemap-container" id="treemap-container"></div>
</template>
<style scoped>
.treemap-container {
width: 100%;
height: 400px;
}
</style>
- 选项式 API:
<script lang="ts">
import { defineComponent } from "vue";
import { VChart, IBarChartSpec, IChart } from "@visactor/vchart";
import type { PropType } from "vue";
interface BarChartProps {
colors?: string[];
data?: any[];
}
export default defineComponent({
props: {
colors: Object as PropType<BarChartProps["colors"]>,
data: Object as PropType<BarChartProps["data"]>,
},
setup() {
let chart: IChart | null = null;
const parseSpec = (chartProps: BarChartProps) => {
const colors = chartProps.colors;
return {
type: "bar",
data: [
{
id: "barData",
values: chartProps.data,
},
],
xField: "name",
yField: "value",
color: {
type: "ordinal",
domain: [],
range: colors,
},
} as IBarChartSpec;
};
const createOrUpdateChart = (chartProps: BarChartProps) => {
const container = document.getElementById("barchart-container");
if (container && !chart) {
chart = new VChart(parseSpec(chartProps), {
dom: container,
});
chart.renderSync();
return true;
} else if (chart) {
chart.updateSpec(parseSpec(chartProps));
chart.renderSync();
return true;
}
return false;
};
const releaseChart = () => {
if (chart) {
chart.release();
chart = null;
}
};
return {
createOrUpdateChart,
releaseChart,
};
},
mounted() {
this.createOrUpdateChart({ colors: this.colors, data: this.data });
},
updated() {
this.createOrUpdateChart({ colors: this.colors, data: this.data });
},
beforeUnmount() {
this.releaseChart();
},
});
</script>
<template>
<h1>this is a demo of barchart</h1>
<div class="barchart-container" id="barchart-container"></div>
</template>
<style scoped>
.barchart-container {
width: 100%;
height: 400px;
}
</style>
结果展示
